﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SSDPNET.Geom;
using ATEC.ATDataCoreNET;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using ATEC.ATCore;
using ATEC.ATDataCoreNET.ATCCL;
using System.Xml.Linq;
using System.Net.Mail;

namespace ATSceneExample
{
    /// <summary>
    /// 功能：ATProject 工程操作工具类
    /// 描述：提供对玄镜图形平台工程的操作功能，包括显示活跃工程信息、获取场景列表、
    ///      加载并参考场景以及后台打开其他工程文件等。
    /// 关键类及说明：
    /// - **ATProject**: 表示一个工程文件，支持加载、查找场景和管理项目内容。
    /// - **ATScene**: 表示工程中的场景，可以加载和操作三维场景数据。
    /// - **ATAttachment**: 表示场景引用，支持场景的嵌套和引用管理。
    /// - **ATDoc**: 表示工程文档对象，用于打开和管理文件。
    /// 注意：
    /// - 工程文件路径需准确配置，否则操作会失败。
    /// - 参考操作中需避免重复加载同名场景。
    /// </summary>
    public class ATProjectMethod
    {
        /// <summary>
        /// 全局变量，用于存储指定工程的完整路径。
        /// </summary>
        public static string sFullPath = "";

        /// <summary>
        /// 默认的目标场景名称，供加载或查找场景时使用。
        /// </summary>
        private static string scenceName = "三维模型空间";

        /// <summary>
        /// 功能：显示当前活跃工程的路径信息
        /// 描述：获取当前活跃的 AT 工程，提取其文件路径并弹窗显示。
        /// 关键类及说明：
        /// - **ATProject**: 表示当前活跃的工程。
        /// 注意：
        /// - 工程必须是有效的，确保其已正确加载。
        /// </summary>
        public static void ShowActiveProject()
        {
            ATProject activeProject = ATEC.ATCore.Session.Entity.GetActiveATProject(); // 获取当前活跃的 AT 工程。
            string projPathName = string.Format("当前工程的路径是{0}", activeProject.GetFileName()); // 格式化工程路径信息。
            MessageBox.Show(projPathName); // 弹窗显示工程路径。
        }

        /// <summary>
        /// 功能：获取当前工程中的场景列表
        /// 描述：遍历当前活跃工程中的所有场景，并输出每个场景的名称和 ID。
        /// 关键类及说明：
        /// - **SceneIndex**: 表示场景的索引，用于快速访问场景 ID。
        /// - **ATScene**: 表示场景对象，包含场景的名称和其他信息。
        /// 注意：
        /// - 仅加载的场景才会被输出，未加载的场景需要显式加载后访问。
        /// </summary>
        public static void GetATSceneFromATProject()
        {
            ATProject activeProject = ATEC.ATCore.Session.Entity.GetActiveATProject(); // 获取当前活跃的 AT 工程。
            string sceneNamesAndId = "当前工程中的场景列表\n"; // 初始化场景信息字符串。

            foreach (SceneIndex index in activeProject.GetSceneIndexCollection()) // 遍历场景索引集合。
            {
                ATScene scene = activeProject.FindLoadedSceneById(index.Id); // 根据 ID 查找加载的场景。
                if (scene == null) continue; // 跳过未加载的场景。

                sceneNamesAndId += $"{scene.SceneName}, ID = {index.Id}\n"; // 拼接场景名称和 ID。
            }

            MessageBox.Show(sceneNamesAndId); // 弹窗显示场景信息。
        }

        /// <summary>
        /// 功能：后台打开指定的 AT 工程
        /// 描述：根据指定路径后台加载工程文件，并返回工程对象。
        /// 关键类及说明：
        /// - **ATDoc**: 表示工程文件的文档对象，用于创建工程实例。
        /// - **ATProjectOwner**: 表示工程所有者，管理工程的生命周期。
        /// - **ATProject**: 工程对象，提供加载和操作功能。
        /// 注意：
        /// - 文件路径需准确，否则会报错提示文件不存在。
        /// - 工程加载模式为读写模式，确保工程可修改。
        /// </summary>
        /// <returns>加载成功返回 ATProject 对象；失败返回 null。</returns>
        public static ATProject OpenOtherProjectBackGroud()
        {
            string exePath = Assembly.GetExecutingAssembly().Location; // 获取当前程序集路径。
            string folder = Path.GetDirectoryName(exePath); // 获取文件所在目录。
            string parentDirectory = Path.GetDirectoryName(folder); // 获取上一级目录。
            string grandparentDirectory = Path.GetDirectoryName(parentDirectory); // 获取上两级目录。

            // 拼接指定工程的完整路径。
            sFullPath = Path.Combine(grandparentDirectory, "SSDPSDK\\ssdpexamplenet\\ProjectExample\\ProjectExample\\DoDraw\\Resource\\示例路线.db");

            if (!File.Exists(sFullPath)) // 检查文件是否存在。
            {
                MessageBox.Show("请检查文件是否存在"); // 弹窗提示错误。
                return null; // 返回 null。
            }

            ATDoc doc = ATDoc.CreateForLocalFile(sFullPath); // 创建工程文档对象。
            ATProjectOwner pro = ATProject.Create(doc, ATProjectOpenMode.ReadWrite); // 创建工程对象并设置为读写模式。

            if (!pro.ATProject.IsLoaded) // 检查工程是否已加载。
            {
                StatusInt openForWriteStatus = StatusInt.Error; // 初始化错误状态。
                ATProjectStatus status = pro.ATProject.LoadATProject(out openForWriteStatus); // 加载工程。

                if (status == ATProjectStatus.Success) // 如果加载成功。
                {
                    MessageBox.Show("文件已打开"); // 弹窗提示。
                    return pro.ATProject; // 返回加载的工程对象。
                }
            }

            return pro.ATProject; // 返回工程对象。
        }

        /// <summary>
        /// 功能：加载并参考指定场景
        /// 描述：后台打开指定工程，加载目标场景，并将其参考到当前活跃工程。
        /// 关键类及说明：
        /// - **ATAttachmentCollection**: 表示场景的参考文件集合，用于判断和添加参考。
        /// - **ATDocMoniker**: 表示工程文档的唯一标识符，用于创建参考。
        /// - **SSDPNET.ATView**: 更新视图工具，用于刷新三维视图。
        /// 注意：
        /// - 场景需唯一，避免重复参考同名文件。
        /// - 若参考操作失败，需检查场景名称和路径。
        /// </summary>
        public static void OpenOtherProjectBackGroud_LoadScene()
        {
            ATProject proj = OpenOtherProjectBackGroud(); // 1. 后台打开工程。
            if (proj == null) return; // 若工程加载失败，退出。

            string projName = proj.GetFileName(); // 获取工程文件名。
            StatusInt errDetails = 0; // 初始化错误信息变量。

            SceneID id = proj.FindSceneIdByName(scenceName); // 查找目标场景 ID。
            ATScene scene = proj.LoadRootSceneById(ref errDetails, id); // 加载场景。
            if (scene == null) return; // 若加载失败，退出。

            ATProject activeProject = ATEC.ATCore.Session.Entity.GetActiveATProject(); // 获取当前活跃工程。
            ATScene mainScene = activeProject.LoadRootSceneById(ref errDetails, id); // 加载当前工程主场景。
            if (mainScene == null || !mainScene.IsValid()) return; // 若主场景无效，退出。

            ATAttachmentCollection attachColl = mainScene.GetATAttachments(); // 获取主场景的参考文件集合。
            if (attachColl != null && attachColl.Count() > 0) // 判断是否存在参考文件。
            {
                foreach (var attach in attachColl) // 遍历参考文件。
                {
                    string attachName = attach.AttachFileName; // 获取参考文件名。
                    if (projName.Contains(attachName) && attach.AttachSceneName.Equals(scenceName)) // 检查是否重复。
                    {
                        MessageBox.Show("当前文件已被参考"); // 提示重复参考。
                        return; // 退出操作。
                    }
                }
            }

            ATDocMoniker docMoniker = proj.GetDocument().GetMoniker(); // 获取文档标识符。
            ATAttachment attachment = mainScene.CreateATAttachment(docMoniker, scene.SceneName); // 创建场景参考。
            if (attachment == null) return; // 若创建失败，退出。

            attachment.NestDepth = 99; // 设置参考嵌套深度。
            attachment.WriteToScene(false); // 写入场景引用。

            int mainSceneViewNum = 2; // 定义视图编号。
            SSDPNET.ATView.ViewUpdateSingle(mainSceneViewNum); // 更新视图。

            MessageBox.Show("参考成功"); // 提示参考成功。
        }
    }
}
